home *** CD-ROM | disk | FTP | other *** search
/ Programming Sound Cards / Programming Sound Cards.iso / sound_57 / sampler.pas < prev    next >
Pascal/Delphi Source File  |  1995-01-01  |  55KB  |  1,266 lines

  1.  
  2.  
  3. Program analog_sound_sampler_with_editor;
  4.  
  5. {$A+,B-,D-,E+,F-,I+,L+,N-,O+,R-,S+}
  6. {$M 16384,0,655360}
  7. { $define debug}
  8. {$ifdef debug}
  9. {$r+}
  10. {$endif}
  11. {$v-}
  12.  
  13. Uses
  14.   dos, crt, graph, rm, menus, fonts, drivers, mousfunc, turbmous,printer;
  15.  
  16. { $define pwm}
  17. {$define sample}
  18.  
  19. {$l samplasm}
  20.  
  21. Const
  22.   {$ifndef pwm}
  23.   titlestring    = 'Sampler  V2.0    (C) R.McKenzie 1989';
  24.   {$endif pwm}
  25.   {$ifdef pwm}
  26.      titlestring = 'PWM Sampler 2.0 (C) R.McKenzie 1989';
  27.   {$endif pwm}
  28.  
  29. (*
  30.  
  31.                    (C) Copyright 1989 by Rowan McKenzie
  32.  
  33.                   You may copy these files  or use the source  code  only
  34.         for non-profit purposes. Please contact me if you wish to use any
  35.         part of the package for commercial purposes.
  36.  
  37.                   Rowan McKenzie
  38.                   35 Moore Ave,
  39.                   Croydon 3136
  40.                   Vic, Australia
  41.  
  42.  
  43.   This program allows the manipulation and replay with chromatic intervals of
  44.     digital sound samples from the keyboard using a guitar fretboard or piano
  45.     keyboard layout. Pitch is determined by a fractional increment technique
  46.     and played through a D/A converter connected to a parallel port or through
  47.     the PC speaker using Pulse Width Modulation.
  48.  
  49.   To create the PWM speaker version, define pwm above, change the pwm
  50.     definition in the samplasm.asm file to true, reassemble samplasm.asm,
  51.     and recompile this file.
  52.  
  53.   To create the D/A version, define da above, change the pwm
  54.     definition in the samplasm.asm file to false, reassemble samplasm.asm,
  55.     and recompile this file.
  56.  
  57.   To use the D/A version, an 8 bit D/A converter will need to be connected
  58.     to the parallel printer port named in the SAMPLER.CNF file.
  59.  
  60.   To use the sample facility an autotriggering A/D converter will need be
  61.     appear at the same port address as the D/A converter, and define sample *)
  62.  
  63.  
  64.  
  65.  
  66. Const cnffilename = 'sampler.cnf';
  67.   clipboardfilename = '.\sampler.clp';
  68.  
  69.   lpt1           = $3bc;          {might be wrong order?}
  70.   lpt2           = $378;
  71.   lpt3           = $278;
  72.  
  73.   default_samplerate = 27;        {initial sample rate=27kHz}
  74.   blocksize      = 4096;          {size of blocks for blockread/write}
  75.  
  76.   bufflength      = $fe00;         {sample buffer size (<64k-16)}
  77.                                   {NOTE: this is the absolute minimum size
  78.                                    allowed here if compatibility between
  79.                                    versions is to be maintained}
  80.  
  81.   maxbeats       = 500;           {no. song elements allowed}
  82.   maxjumps       = 20;            {no. jumps allowed inside songs}
  83.   maxsymbols     = 15;            {no. symbols in songs allowed}
  84.   maxfiles       = 301;           {no. files allowed in directory list (set
  85.                                 according to how many will fit on directory
  86.                                 display +1)}
  87.  
  88.   bigemptystring = '                                                                            ';
  89.   esc            = #$1b;
  90.   introdelay     = 700;           {delay for user to read intro screen(x10ms)}
  91.  
  92.   dialogbcolor   = red;
  93.   dialogcolor    = white;
  94.   clickbcolor    = red;
  95.   clickcolor     = white;
  96.   screencolor    = green;
  97.   dirbcolor      = green;
  98.   dircolor       = black;
  99.   dirhcolor      = white;
  100.   panelcolor     = lightgreen;
  101.   wavecolor      = white;
  102.   waveboxcolor   = lightred;
  103.   hotcolor       = white;
  104.   hotbcolor      = lightblue;
  105.   titlecolor     = black;
  106.   tuningbcolor   = blue;
  107.   tuningcolor    = white;
  108.   timerbcolor    = green;
  109.   timercolor     = white;
  110.   drawcolor      = yellow;
  111.  
  112.   cornersize     = 20;            {size of corner arc}
  113.   arrowxsize     = 8;             {width of arrow pointers}
  114.   arrowysize     = 9;             {height       "         }
  115.   arrowxoff      = 4;            {offset to center of arrow (arrowxsize div 2)}
  116.   arrowpoints    = 8;             {no. points in arrow}
  117.  
  118.  
  119.  
  120.   {patterns for arrow pointers}
  121.  
  122.   uparrowshape : Array[1..arrowpoints] Of pointtype =
  123.   ((x : 4; y : 0), (x : 0; y : 4), (x : 3; y : 4), (x : 3; y : 9),
  124.    (x : 5; y : 9), (x : 5; y : 4), (x : 8; y : 4), (x : 4; y : 0));
  125.   downarrowshape : Array[1..arrowpoints] Of pointtype =
  126.   ((x : 104; y : 9), (x : 100; y : 5), (x : 103; y : 5), (x : 103; y : 0),
  127.    (x : 105; y : 0), (x : 105; y : 5), (x : 108; y : 5), (x : 104; y : 9));
  128.  
  129.   tuningshapepoints = 4;
  130.   tuningrshape : Array[1..tuningshapepoints] Of polypoint =
  131.   ((x : 10; y : 8), (x : 0; y : 12), (x : 0; y : 4), (x : 10; y : 8));
  132.   tuninglshape : Array[1..tuningshapepoints] Of polypoint =
  133.   ((x : 0; y : 8), (x : 10; y : 12), (x : 10; y : 4), (x : 0; y : 8));
  134.  
  135.   introyoff      = 3;             {intro information position}
  136.   plotxoffset    = arrowxoff;     {indent from edge of screen for wave}
  137.   dirnamefieldwidth = 14;         {field width for directory names}
  138.  
  139.  
  140.   {modified codes to represent special keys in one byte}
  141.  
  142.   spctrl = #128; splshift = #129; sprshift = #130; spalt = #131; spcaps = #132;
  143.   spnum = #133; spscroll = #134; sphome = #135; spsys = #136; spuparrow = #137;
  144.   sppgup = #138; spprtsc = #139; spleftarrow = #140; sp5 = #141;
  145.   sprightarrow = #142; spminus = #143; spend = #144; spdownarrow = #145;
  146.   sppgdn = #146; spplus = #147; spins = #148; spdel = #149; spf1 = #151;
  147.   spf2 = #152; spf3 = #153; spf4 = #154; spf5 = #155; spf6 = #156; spf7 = #157;
  148.   spf8 = #158; spf9 = #159; spf10 = #160;
  149.  
  150.  
  151.   {the following arrays map the keyboard to a set of notes (guitar or piano)
  152.     where -13 is an invalid letter}
  153.  
  154. Type kbdmaptype = Array[''''..']'] Of Integer;
  155.  
  156. Const kbdmapguitar : kbdmaptype =
  157.   ( {'} 3, -13, -13, -13, -13, -5, 13, -4, -3, 12, 3, 4, 5, 6, 7, 8,
  158.    9, 10, 11, -13, 2, -13, 14, -13, -13, -13,
  159.    {A} -7, -8, -10, -5, 0, -4, -3, -2, 5, -1, 0, 1, -6, -7, 6, 7,
  160.    -2, 1, -6, 2, 4, -9, -1, -11, 3, -12, 8, 15, 9);
  161.  
  162.  
  163.   kbdmappiano : kbdmaptype =
  164.   ( {'} 10, -13, -13, -13, -13, 5, 20, 7, 9, 18, 3, -13, 6, 8, 10, -13,
  165.    13, 15, -13, -13, 8, -13, 22, -13, -13, -13,
  166.    {A} -13, 0, -3, -4, 7, -2, -13, 1, 16, 3, -13, 6, 4, 2, 17, 19, 4,
  167.    9, -6, 11, 14, -1, 5, -5, 12, -7, 21, -13, 23);
  168.  
  169.  
  170.   {the following table maps scan codes to ascii values}
  171.  
  172.   scanmap : Array[0..255] Of Char =
  173.  
  174.   ( {0} #0, esc, '1', '2', '3', '4', '5', '6', '7', '8',
  175.    {10} '9', '0', '-', '=', #8, #9, 'Q', 'W', 'E', 'R',
  176.    {20} 'T', 'Y', 'U', 'I', 'O', 'P', '[', ']', #13, spctrl,
  177.    {30} 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';',
  178.    {40} '''', '`', splshift, '\', 'Z', 'X', 'C', 'V', 'B', 'N',
  179.    {50} 'M', ',', '.', '/', sprshift, #0, spalt, ' ', spcaps, spf1,
  180.    {60} spf2, spf3, spf4, spf5, spf6, spf7, spf8, spf9, spf10, spnum,
  181.    {70} spscroll, sphome, spuparrow, sppgup, spminus, spleftarrow, sp5,
  182.    sprightarrow, spplus, spend,
  183.    {80} spdownarrow, sppgdn, spins, spdel, #0, #0, #0, #0, #0, #0,
  184.    {90} #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
  185.    {100} #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
  186.    {110} #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
  187.    {120} #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
  188.    {130} #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
  189.    {140} #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
  190.    {150} #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
  191.    {160} #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
  192.    {170} #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
  193.    {180} #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
  194.    {190} #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
  195.    {200} #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
  196.    {210} #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
  197.    {220} #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
  198.    {230} #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
  199.    {240} #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
  200.    {250} #0, #0, #0, #0, #0, #0);
  201.  
  202.  
  203. Type
  204.   bufferp        = ^buffertype;
  205.   buffertype =
  206.            Array[0..bufflength] Of Byte;      {holds samples, plus overflow space}
  207.   dummyp         = ^dummytype;
  208.   dummytype      = Array[1..128] Of Byte; {overflow area for buffers}
  209.   directory_type = Array[1..maxfiles] Of String[12]; {holds directory entries}
  210.   songentry = Record              {holds one entry of a song file}
  211.                 note        : Real; {do preprocessing to real beofre play time}
  212.                 duration    : Integer;
  213.               End;
  214. Type filednote = Record
  215.                    octave, note, staccato : Byte;
  216.                    duration : Integer;
  217.                  End;
  218.   notefile       = File Of filednote;
  219.  
  220.  
  221.  
  222. Var i, j, k, m, viewleft, viewright,
  223.                                 {3 screen pointers representing left, right,
  224.                                  loop pointers in sound sample}
  225.   leftord, rightord, loopord : LongInt;
  226.  
  227.   x1copy, x2copy,
  228.   arrowlowy, arrowhighy,          {y positions of the 3 pointers}
  229.   directoryyoff,                  {directory listing y position}
  230.   dirnamesperline,                {no. diectory entries per line}
  231.   increment, tune,                {pitch parameters}
  232.   wavebottom, wavetop, wavescale, {position and size of waveform to be plotted}
  233.   graphdriver, graphmode,
  234.   lastx, lasty   : Integer;
  235.   bufstart, bufloop, bufend : Word; {offsets of buffer positions for the
  236.                                      3 pointers}
  237.   uparrowp, downarrowp : Pointer; {points to image areas for arrows}
  238.   tinterval      : Integer;       {interval eg. 64=crotchet, 32=quaver}
  239.   quickexit      : Boolean;
  240.   modulus,                        {counts interrupts for tinterval}
  241.   tconstant      : Byte;          {interrupt rate}
  242.   sysspeed,                       {indicates system speed for duration calcs}
  243.   incdef         : Integer;       {sets default pitch}
  244.   songspeed      : Real;          {determines overall song speed}
  245.   default_system,                 {initial value of system type (AT,XT etc)}
  246.   c, cdum        : Char;
  247.   kbdmap         : kbdmaptype;    {holds current keyboard map}
  248.   trigger,                        {trigger level required to begin sampling}
  249.   samplerate     : Integer;       {sample rate (kHz)}
  250.   dir            : directory_type; {holds list of file names in directory}
  251.   releasestate, timer,
  252.   copying,                        {indicates copy procedure in progress}
  253.   Release, loop,                  {current state of release & loop}
  254.   song           : Boolean;       {indicates song mode active}
  255.   registersrec   : registers;
  256.   default_daport,
  257.   default_kbdmap,
  258.   default_sound_file, systemname,
  259.   songfilename,
  260.   path, str1,
  261.   workfile       : String;
  262.   kbdmode        : Boolean;       {indicates special kbd processing required}
  263.   kbdflag,                        {indicates key pressed (custom kbd service)}
  264.   keyval         : Byte;          {holds key value            "              }
  265.   daout,                          {port for d/a converter}
  266.   crotchet,                       {holds tconstant for a crotchet duration}
  267.   filesavail     : Integer;       {number of sound files found in directory}
  268.   cnffile        : Text;          {holds default information}
  269.   songend        : Integer;       {points to end of current song}
  270.   songarray      : Array[1..maxbeats] Of songentry; {holds current song}
  271.   dp, lastdialogentry, dialoghead : dialogentryp;
  272.   tuningcp, timercp, lastcp,
  273.   cp             : clickboxtypep;
  274.   goodbye        : Boolean;
  275.   storagep       : Pointer;       {general image storage pointer}
  276.   cutleft, cutright : LongInt;    {left/right points of cut region}
  277.   cutactive,                      {indicates data has been cut to disk}
  278.   cutboxactive   : Boolean;       {indicates cut box currently active}
  279.   f              : File;          {general purpose file pointer}
  280.   bufflen        : word;
  281.   buffer, bufferw : bufferp;      {pointer to sound storage buffer,
  282.                                    and work buffer}
  283.   dummy          : dummyp;        {overflow area for bufferw}
  284.   fsong          : notefile;
  285.   anote          : filednote;
  286.   songp          : Integer;
  287.   oldtimer, songloop : Boolean;
  288.   c1             : Char;
  289.   altdown        : Boolean;       {indicates alt key is currently down}
  290.   zoom           : Boolean;
  291.   customkbd      : boolean;
  292.  
  293.   Procedure initial; External;    {external assembler routines (samplasm.asm)}
  294.   Procedure restore; External;
  295.   Procedure sample; External;
  296.   Procedure replay; External;
  297.   Procedure replayt; External;
  298.   Procedure scalewave; External;
  299.   procedure echo; external;
  300.  
  301.   procedure replay_sound(timer:boolean);
  302.  
  303.   {calls appropriate replay module depending on whether timer operation is
  304.    required}
  305.  
  306.   begin {replay_sound}
  307.     if timer then
  308.       replayt
  309.     else
  310.       replay;
  311.   end; {replay_sound}
  312.  
  313.  
  314.  
  315.   {$i sampler.inc}
  316.  
  317.  
  318.  
  319.   Function mymousemoved : Boolean;
  320.  
  321.     { like mousemoved, but is aware of custom kbd service}
  322.  
  323.   Var moved      : Boolean;
  324.     Inc            : Integer;
  325.  
  326.   Begin                           {mymousmoved}
  327.     moved := False;
  328.     If keypress And (scanmap[keyval] In [spuparrow, spdownarrow, spleftarrow,
  329.                      sprightarrow]) Then {cursor key}
  330.     Begin
  331.       Inc := 10;
  332.       If mem[0:$417] And 2 > 0 Then {if left shift down}
  333.         Inc := 1;
  334.       Case scanmap[keyval] Of     {arrow keys control mouse}
  335.         spuparrow : Begin mousey := mousey-Inc; moved := True; End;
  336.         spdownarrow : Begin mousey := mousey+Inc; moved := True; End;
  337.         spleftarrow : Begin mousex := mousex-Inc; moved := True; End;
  338.         sprightarrow : Begin mousex := mousex+Inc; moved := True; End;
  339.       End;                        {case}
  340.       If moved Then
  341.       Begin
  342.         kbdflag := 0;
  343.         keyval := keyval+128;     {allow autorepeat}
  344.       End;
  345.     End;
  346.     mymousemoved := moved Or mousemoved;
  347.   End;                            {mymousemoved}
  348.  
  349.  
  350.   Procedure enable_custom_kbd;
  351.  
  352. { enables custom kbd handler.
  353.  waits if ctrl,alt or caps lock down or active. bios seems to be confused if
  354.  first kbd signal is release of a key}
  355.  
  356.   Begin                           {enable_custom_kbd}
  357.     Repeat Until (mem[0:$417] And $4c = 0)
  358.     And (mem[0:$418] And $40 = 0);
  359.     kbdmode := True;
  360.   End;                            {enable_custom_kbd}
  361.  
  362.  
  363. Begin                             {main}
  364.  
  365.   customkbd:=false;
  366.   WriteLn(MaxAvail, ' bytes free');
  367.   ExitProc := @samplerexit;       {install custom error handler}
  368.   heaperrorinit;                  {install custom heap error handler}
  369.   If not mouseinit Then           {if no mouse driver found}
  370.   Begin
  371.     WriteLn;
  372.     WriteLn;
  373.     WriteLn('No MSmouse driver found.');
  374.     WriteLn;
  375.     WriteLn('Cursor may be controlled using arrow keys');
  376.     WriteLn('  and the following buttons:');
  377.     WriteLn;
  378.     WriteLn('  Alt       = left mouse button');
  379.     WriteLn('  Caps Lock = right mouse button');
  380.     WriteLn;
  381.     WriteLn('Press a key to continue...');
  382.     c := readkey;
  383.   End;
  384.   initialise;                     {set up graphics mode, defaults etc}
  385.   update_display;                 {fill screen with info}
  386.   mousearrowon;
  387.   keyval := 127;                  {clear custom key service info}
  388.   kbdmode := False;
  389.   initial;                {replace kbd service now incase exit via samplerexit}
  390.   customkbd:=true;
  391.   c := ' ';                       {no sound immediately for loop}
  392.   enable_custom_kbd;
  393.   Repeat
  394.  
  395.     If song And
  396.     Not(keypress And (scanmap[keyval] = sprshift)) Then
  397.       {if song mode and no shifts down}
  398.     Begin
  399.       kbdflag := 0;
  400.       tinterval := Round(songarray[songp].duration/songspeed);
  401.       increment := Round(tune*songarray[songp].note);
  402.       If songarray[songp].note = -13 Then
  403.         increment := 0;           {silence for rest}
  404.       Release := releasestate;
  405.       replay_sound(timer);
  406.       Release := True;
  407.       Inc(songp);
  408.       song := (songp <= songend);
  409.       If Not song Then
  410.         If songloop Then
  411.         Begin
  412.           songp := 1;
  413.           song := True;
  414.         End
  415.         Else
  416.         Begin
  417.           menustructure[4].entry[2].visible := True; {play_song}
  418.           tinterval := crotchet;
  419.           timer := oldtimer;
  420.         End;
  421.     End;
  422.  
  423.     If mymousemoved Then          {track mouse and keyboard}
  424.     Begin
  425.       updatemousepos;
  426.       If keypress And (scanmap[keyval] In [spuparrow, spdownarrow, spleftarrow,
  427.                        sprightarrow]) Then {cursor key}
  428.       Begin
  429.         Repeat Until keyval > 127; {wait for keyrelease}
  430.         kbdflag := 0;
  431.       End;
  432.     End;
  433.  
  434.     If keypress And (scanmap[keyval] In ['''', ','..']']) Then {if note key}
  435.     Begin
  436.       kbdflag := 0;
  437.       c := scanmap[keyval];
  438.       If kbdmap[c] > -13 Then     {if valid note}
  439.       Begin
  440.         increment := get_inc(tune, c);
  441.         Release := releasestate;
  442.         replay_sound(timer);                   {then play}
  443.         Release := True;
  444.       End;
  445.     End
  446.  
  447.     Else
  448.     Begin
  449.       If ((mousekeys > 1)
  450.          Or (keypress And (scanmap[keyval] In [spctrl, spcaps])))
  451.          And (cutboxactive Or song) Then
  452.       Begin                        {if right/middle button or ctrl/caps lock}
  453.         If cutboxactive Then
  454.         Begin
  455.           mousearrowoff;
  456.           erase_cutbox;
  457.           cutboxactive := False;
  458.           mousearrowon;
  459.           activate_menu_options(False); {disable cut box options}
  460.           If keypress And Not(scanmap[keyval] = sprshift) Then
  461.           Begin
  462.             Repeat Until keyval > 127; {wait for keyrelease}
  463.             kbdflag := 0;
  464.           End;
  465.         End
  466.         Else
  467.           If song Then
  468.           Begin
  469.             song := False;
  470.             menustructure[4].entry[1].visible := True; {song}
  471.             mousearrowoff;
  472.             draw_menu_box(4, 1, False);
  473.             mousearrowon;
  474.             tinterval := crotchet;
  475.             timer := oldtimer;
  476.             If keypress And Not(scanmap[keyval] = sprshift) Then
  477.             Begin
  478.               Repeat Until keyval > 127; {wait for keyrelease}
  479.               kbdflag := 0;
  480.             End;
  481.           End;
  482.         Repeat Until mousekeys = 0;
  483.       End
  484.  
  485.       Else
  486.         If (mousekeys > 0) Or
  487.         (keypress And (scanmap[keyval] In [spctrl, spcaps, spalt])) Then
  488.         Begin
  489.           settextstyle(defaultfont, horizdir, 1);
  490.           i := click_selection(tuningcp, cornersize,
  491.                                getmaxy-textheight(' ')*2);
  492.           If i > -1 Then          {one of the tuning boxes selected?}
  493.           Begin
  494.             Case i Of
  495.               1 : If tune > 1 Then {octave down}
  496.                     tune := tune Div 2;
  497.               2 : If tune > 1 Then {tune down coarse}
  498.                     tune := tune-5;
  499.               3 : If tune > 1 Then {tune down fine}
  500.                     Dec(tune);
  501.               4 : If tune < $1ae8 Then {tune up fine}
  502.                     Inc(tune);
  503.               5 : If tune < $1ae8 Then {tune up coarse}
  504.                     tune := tune+5;
  505.               6 : If tune < $1ae8 Then {note $1ae9 causes increment > ffff}
  506.                     tune := tune*2; {up octage}
  507.               7 : tune := incdef; {reset tuning}
  508.             End;                  {case}
  509.             increment := get_inc(tune, 'E'); {calculate new tuning info}
  510.             i := -1;              {not menu item}
  511.             If keypress And Not(scanmap[keyval] = sprshift) Then
  512.             Begin                 {if key pressed}
  513.               Repeat Until keyval > 127;
  514.               kbdflag := 0;
  515.             End;
  516.             Repeat Until mousekeys = 0; {wait for button release}
  517.           End
  518.  
  519.           Else
  520.           Begin
  521.             i := click_selection(timercp,
  522.                                  getmaxx-cornersize-textwidth('            '),
  523.                                  getmaxy-textheight(' ')*2);
  524.             If i > -1 Then        {one of the timer boxes selected?}
  525.             Begin
  526.               Case i Of
  527.                 1 : songspeed := songspeed*0.85;
  528.                 2 : songspeed := songspeed*0.95;
  529.                 3 : songspeed := songspeed/0.95;
  530.                 4 : songspeed := songspeed/0.85;
  531.               End;                {case}
  532.               tinterval := Round(crotchet/songspeed); {timer duration}
  533.               i := -1;            {not menu item}
  534.               If keypress And Not(scanmap[keyval] = sprshift) Then
  535.               Begin               {if key pressed}
  536.                 Repeat Until keyval > 127;
  537.                 kbdflag := 0;
  538.               End;
  539.               Repeat Until mousekeys = 0; {wait for button release}
  540.             End
  541.  
  542.             Else
  543.             Begin
  544.               i := arrow_selection; {trying to drag an arrow?}
  545.               If i > -1 Then
  546.               Begin
  547.                 j := mousex;      {remember mouse position}
  548.                 k := mousey;
  549.                 altdown := keypress And (scanmap[keyval] = spalt);
  550.                 If altdown Then
  551.                   Repeat Until keyval > 127; {wait for alt release}
  552.                 While (arrow_selection = i) And ((mousekeys = 1) Or altdown) Do
  553.                 Begin             {while button down}
  554.                   If mymousemoved Then {track mouse/kbd}
  555.                   Begin
  556.                     mousey := k;  {keep mouse height constant}
  557.                     updatemousepos; {replot mouse}
  558.                     mousearrowoff;
  559.                     Case i Of
  560.                       1 : move_pointers(mousex-j, 0, 0); {left arrow}
  561.                       2 : move_pointers(0, mousex-j, 0); {right arrow}
  562.                       3 : move_pointers(0, 0, mousex-j); {loop arrow}
  563.                     End;          {case}
  564.                     mousearrowon;
  565.                     j := mousex;  {remember last mouse pos}
  566.                     If keypress And
  567.                       (scanmap[keyval] In [spuparrow, spdownarrow,
  568.                                            spleftarrow, sprightarrow])
  569.                     Then          {cursor key}
  570.                     Begin
  571.                       Repeat Until keyval > 127; {wait for keyrelease}
  572.                       kbdflag := 0;
  573.                     End;
  574.                   End;
  575.                   altdown := altdown And {wait for second alt}
  576.                   Not(keypress And (scanmap[keyval] = spalt));
  577.  
  578.                 End;
  579.                 altdown := False;
  580.                 If keypress And Not(scanmap[keyval] = sprshift) Then
  581.                 Begin
  582.                   Repeat Until keyval > 127; {wait for keyrelease}
  583.                   kbdflag := 0;
  584.                 End;
  585.                 set_bounds;       {recalculate buffer params}
  586.                 i := -1;          {not menu item}
  587.               End
  588.  
  589.               Else                {inside wave box?}
  590.                 If (mousey > wavetop) And (mousey < wavebottom)
  591.                   And (mousex >= plotxoffset) And
  592.                   (mousex <= getmaxx-plotxoffset) And
  593.                   Not cutboxactive Then
  594.                 Begin
  595.                   If (mousekeys = 1)
  596.                     Or (keypress And (scanmap[keyval] = spalt)) Then
  597.                   Begin
  598.                     mousearrowoff;
  599.                     erase_cutbox;
  600.                     mousearrowon;
  601.                     activate_menu_options(True);
  602.                                   {enable options requiring cut box}
  603.                     cutboxactive := True;
  604.                     cutleft := index(mousex);
  605.                     lastx := mousex; {remember mouse x position}
  606.                     altdown := keypress And (scanmap[keyval] = spalt);
  607.                     If altdown Then
  608.                       Repeat Until keyval > 127; {wait for alt release}
  609.                     For j := wavetop-1 To wavebottom+1 Do {mark left box edge}
  610.                       putpixel(mousex, j, getmaxcolor-getpixel(mousex, j));
  611.                     Repeat
  612.                       If mymousemoved Then {track mouse/kbd}
  613.                       Begin
  614.                         mousearrowoff;
  615.                         If mousex < plotxoffset Then
  616.                                            {limit mouse range to wavebox}
  617.                           mousex := plotxoffset;
  618.                         If mousex > getmaxx-plotxoffset Then
  619.                           mousex := getmaxx-plotxoffset;
  620.                         If mousex > lastx Then
  621.                                            {moved to right, extend box edges}
  622.                           For i := lastx+1 To mousex Do
  623.                           Begin
  624.                             If (getmaxcolor > 1) Or Odd(i) Then
  625.                             Begin
  626.                               putpixel(i, wavetop-1,
  627.                                        getmaxcolor-getpixel(i, wavetop-1));
  628.                               putpixel(i, wavebottom+1,
  629.                                        getmaxcolor-getpixel(i, wavebottom+1));
  630.                             End;
  631.                           End
  632.                         Else
  633.                           If mousex < lastx Then
  634.                             For i := lastx Downto mousex+1 Do
  635.                               If (getmaxcolor > 1) Or Odd(i) Then
  636.                               Begin {moved to left, extend box edges}
  637.                                 putpixel(i, wavetop-1,
  638.                                          getmaxcolor-getpixel(i, wavetop-1));
  639.                                 putpixel(i, wavebottom+1,
  640.                                      getmaxcolor-getpixel(i, wavebottom+1));
  641.                               End;
  642.                         mousearrowon;
  643.                         updatemousepos;
  644.                         lastx := mousex;
  645.                         If keypress And
  646.                           (scanmap[keyval] In [spuparrow, spdownarrow,
  647.                                                spleftarrow, sprightarrow]) Then 
  648.                         Begin                        {cursor key}
  649.                           Repeat Until keyval > 127; {wait for keyrelease}
  650.                           kbdflag := 0;
  651.                         End;
  652.                       End;
  653.                       altdown := altdown And
  654.                       Not(keypress And (scanmap[keyval] = spalt));
  655.                     Until (mousekeys = 0) And Not altdown;
  656.                                   {continue until button released}
  657.  
  658.                     If keypress And Not(scanmap[keyval] = sprshift)
  659.                     Then
  660.                     Begin
  661.                       Repeat Until keyval > 127; {wait for keyrelease}
  662.                       kbdflag := 0;
  663.                     End;
  664.                     cutright := index(mousex);
  665.                     If cutleft <> cutright Then
  666.                       For j := wavetop-1 To wavebottom+1 Do {draw far side}
  667.                         putpixel(mousex, j, getmaxcolor-getpixel(mousex, j));
  668.                     If cutright < cutleft Then {make sure cutleft<=cutright}
  669.                     Begin
  670.                       i := cutleft;
  671.                       cutleft := cutright;
  672.                       cutright := i;
  673.                     End;
  674.                     i := -1;      {not a menu item}
  675.                   End
  676.                   Else
  677.                     If zoom Then
  678.                     Begin         {zoom mode means manual drawing}
  679.                       mousearrowoff;
  680.                       erase_cutbox;
  681.                       lastx := mousex;
  682.                       lasty := wavebottom-buffer^[index(mousex)] Div wavescale;
  683.                       buffer^[index(mousex)] := (wavebottom-mousey)*wavescale;
  684.                       setcolor(drawcolor);
  685.                       line(lastx, lasty, lastx, mousey);
  686.                       mousearrowon;
  687.                       lasty := mousey;
  688.                       altdown := keypress And (scanmap[keyval] = spcaps);
  689.                       If altdown Then
  690.                         Repeat Until keyval > 127; {wait for caps release}
  691.                       Repeat
  692.                         If mymousemoved Then {track mouse/kbd}
  693.                         Begin
  694.                           mousearrowoff;
  695.                           If mousex < plotxoffset Then
  696.                                             {limit mouse range to wavebox}
  697.                             mousex := plotxoffset;
  698.                           If mousex > getmaxx-plotxoffset Then
  699.                             mousex := getmaxx-plotxoffset;
  700.                           If mousey < wavetop Then
  701.                             mousey := wavetop;
  702.                           If mousey > wavebottom Then
  703.                             mousey := wavebottom;
  704.                           line(lastx, lasty, mousex, mousey);
  705.                           m := index(mousex)-index(lastx); {delta x}
  706.                           For i := index(lastx)+1 To index(mousex) Do
  707.                                              {plot line in buffer}
  708.                             buffer^[i] := Round((wavebottom-
  709.                                                 ((i-index(lastx))*
  710.                                                 (mousey-lasty) Div m+lasty))*
  711.                                                 wavescale);
  712.                           For i := index(lastx)-1 Downto index(mousex) Do
  713.                             buffer^[i] := Round((wavebottom-
  714.                                                 ((i-index(lastx))*
  715.                                                 (mousey-lasty) Div m+lasty))*
  716.                                                 wavescale);
  717.                           lastx := mousex;
  718.                           lasty := mousey;
  719.                           mousearrowon;
  720.                           updatemousepos;
  721.                           If keypress
  722.                             And (scanmap[keyval]
  723.                                    In [spuparrow, spdownarrow,
  724.                                        spleftarrow, sprightarrow])
  725.                           Then           {cursor key}
  726.                           Begin
  727.                             Repeat Until keyval > 127; {wait for keyrelease}
  728.                             kbdflag := 0;
  729.                           End;
  730.                         End;
  731.                         altdown := altdown And {wait for second alt}
  732.                         Not(keypress And (scanmap[keyval] = spcaps));
  733.                       Until (mousekeys = 0) And Not altdown;
  734.                                   {continue until button released}
  735.  
  736.                       If keypress And Not(scanmap[keyval] = sprshift)
  737.                       Then
  738.                       Begin
  739.                         Repeat Until keyval > 127; {wait for keyrelease}
  740.                         kbdflag := 0;
  741.                       End;
  742.                       mousearrowoff;
  743.                       draw_wave;
  744.                       mousearrowon;
  745.                       i := -1;    {not a menu item}
  746.                     End;
  747.                 End
  748.  
  749.                 Else
  750.                 Begin             {might have been a menu heading}
  751.                   j := -1;        {default no submenu chosen}
  752.                   i := menu_selection(horizdir, 0);
  753.                   If i > -1 Then
  754.                   Begin           {was menu heading}
  755.                     If menustructure[i].nentries = 1 Then
  756.                     Begin
  757.                       j := 1;     {if no subtopics then remember it
  758.                                    was menu heading}
  759.                       mousearrowoff;
  760.                       draw_menu_box(i, j, True); {highlight submenu selection}
  761.                       mousearrowon;
  762.                     End
  763.                     Else
  764.                     Begin         {wait for subtopic to be chosen}
  765.                       kbdmode := False;
  766.                       mousearrowoff;
  767.                       draw_menu_box(i, 1, True); {highlight heading}
  768.                       draw_menu_column(i); {show submenu for that column}
  769.                       mousearrowon;
  770.                       Repeat Until mousekeys = 0;
  771.                       Repeat
  772.                         Repeat
  773.                           c := trackmouse;
  774.                         Until (mousekeys > 0) Or (c = ^c);
  775.                         If mousekeys = 1 Then {if left button}
  776.                           j := menu_selection(vertdir, i)
  777.                                         {calculate which column was selected}
  778.                         Else
  779.                           j := -1; {other buttons cancel}
  780.                       Until (mousekeys > 1) Or (j > -1);
  781.                                         {wait for valid select or cancel}
  782.                       mousearrowoff;
  783.                       If mousekeys > 1 Then
  784.                         remove_menu_column(i); {if cancel, erase submenu}
  785.                       If j > -1 Then
  786.                         draw_menu_box(i, j, True);
  787.                                         {highlight submenu selection}
  788.                       Repeat Until mousekeys = 0;
  789.                       mousearrowon;
  790.                       enable_custom_kbd;
  791.                     End;
  792.  
  793.                     If j > -1 Then {if a valid menu item was selected}
  794.                     Begin
  795.                       kbdmode := False;
  796.                       Case menustructure[i].entry[j].selection Of
  797.  
  798.                         concert_a :
  799.                           Begin
  800.                             sound(440); {concert A}
  801.                             Repeat Until mousekeys > 1;
  802.                             nosound;
  803.                             mousearrowoff;
  804.                             remove_menu_column(i);
  805.                             draw_cutbox;
  806.                             mousearrowon;
  807.                           End;
  808.  
  809.                         monitor:
  810.                           Begin
  811.                             k := tconstant;
  812.                             tconstant := Round(1.19318e3/17);
  813.                             kbdflag := 0;
  814.                             enable_custom_kbd;
  815.                             echo;    {echo a/d to d/a}
  816.                             kbdmode := False;
  817.                             tconstant := k;
  818.                             mousearrowoff;
  819.                             remove_menu_column(i);
  820.                             draw_cutbox;
  821.                             mousearrowon;
  822.                           End;
  823.  
  824.                         _zoom :
  825.                           Begin
  826.                             mousearrowoff;
  827.                             zoom := Not(zoom);
  828.                             If zoom Then
  829.                             Begin
  830.                               viewleft := cutleft;
  831.                               viewright := cutleft+getmaxx-plotxoffset*2;
  832.                             End
  833.                             Else
  834.                             Begin
  835.                               viewleft := 0;
  836.                               viewright := bufflength;
  837.                             End;
  838.                             cutboxactive := cutboxactive And Not zoom;
  839.                             remove_menu_column(i);
  840.                             draw_wave;
  841.                             draw_cutbox;
  842.                             activate_menu_options(cutboxactive);
  843.                             mousearrowon;
  844.                           End;
  845.  
  846.                         read_song_file :
  847.                           Begin
  848.                             song := False;
  849.                             loadsong;
  850.                             menustructure[4].entry[2].visible := True;
  851.                                                              {play_song}
  852.                             mousearrowoff;
  853.                             remove_menu_column(i);
  854.                             mousearrowon;
  855.                           End;
  856.  
  857.                         play_song :
  858.                           Begin
  859.                             song := False;
  860.                             If songfilename <> '' Then
  861.                             Begin
  862.                               song := True;
  863.                               oldtimer := timer;
  864.                               timer := True;
  865.                               songp := 1;
  866.                               New(dp);
  867.                               With dp^ Do
  868.                               Begin
  869.                                 title := 'Looped play?';
  870.                                 argtype := _boolean;
  871.                                 booleanresult := False;
  872.                                 next := Nil;
  873.                               End;
  874.                               settextstyle(defaultfont, horizdir, 1);
  875.                               dialog_box(dp, dialogbcolor, dialogcolor, False);
  876.                               songloop := dp^.booleanresult;
  877.                               Dispose(dp);
  878.                               menustructure[4].entry[2].visible := False;
  879.                                                                    {play_song}
  880.                               mousearrowoff;
  881.                               remove_menu_column(i);
  882.                               mousearrowon;
  883.                             End;
  884.                           End;
  885.  
  886.                         cut, _copy :
  887.                           Begin
  888.                             write_data(clipboardfilename, cutleft, cutright);
  889.                             cutactive := True;
  890.                             mousearrowoff;
  891.                             remove_menu_column(i);
  892.                             erase_cutbox;
  893.                             If menustructure[i].entry[j].selection = cut Then
  894.                             Begin
  895.                               cut_region(cutleft, cutright);
  896.                               draw_wave;
  897.                             End;
  898.                             cutboxactive := False;
  899.                             activate_menu_options(False);
  900.                                                       {disable cut box options}
  901.                             mousearrowon;
  902.                           End;
  903.  
  904.                         paste, mix :
  905.                           Begin
  906.                             load_sound_file(clipboardfilename, cutleft,
  907.                                             cutright,
  908.                                             (menustructure[i].entry[j].
  909.                                              selection = mix));
  910.                             mousearrowoff;
  911.                             remove_menu_column(i);
  912.                             draw_wave;
  913.                             draw_cutbox;
  914.                             mousearrowon;
  915.                           End;
  916.  
  917.                         mirror_segment :
  918.                           Begin
  919.                             mousearrowoff;
  920.                             mirror_data;
  921.                             remove_menu_column(i);
  922.                             draw_wave;
  923.                             draw_cutbox;
  924.                             mousearrowon;
  925.                           End;
  926.  
  927.                         clear :
  928.                           Begin
  929.                             mousearrowoff;
  930.                             cut_region(cutleft, cutright);
  931.                             remove_menu_column(i);
  932.                             draw_wave;
  933.                             draw_cutbox;
  934.                             mousearrowon;
  935.                           End;
  936.  
  937.                         _scale_envelope :
  938.                           Begin
  939.                             scale_envelope;
  940.                             mousearrowoff;
  941.                             remove_menu_column(i);
  942.                             draw_wave;
  943.                             draw_cutbox;
  944.                             mousearrowon;
  945.                           End;
  946.  
  947.                         _help :
  948.                           Begin
  949.                             dialoghead := Nil;
  950.                             New(dp);
  951.                             dp^.title :=
  952. '  Help for '+titlestring;
  953.                             dp^.argtype := _none;
  954.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  955.                             New(dp);
  956.                             dp^.title :=
  957. 'Select option from menu at top of screen using left mouse button or Alt key.';
  958.                             dp^.argtype := _none;
  959.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  960.                             New(dp);
  961.                             dp^.title :=
  962. 'Generally, the left mouse button or Alt key select objects, while the right button';
  963.                             dp^.argtype := _none;
  964.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  965.                             New(dp);
  966.                             dp^.title :=
  967. 'or Ctrl key cancel operations.';
  968.                             dp^.argtype := _none;
  969.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  970.                             New(dp);
  971.                             dp^.title :=
  972. 'Boxes at lower left on screen alter tuning and octave. Reset restores default pitch.';
  973.                             dp^.argtype := _none;
  974.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  975.                             New(dp);
  976.                             dp^.title :=
  977. 'Boxes at lower right on screen alter timer period.';
  978.                             dp^.argtype := _none;
  979.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  980.                             New(dp);
  981.                             dp^.title :=
  982. 'Wave box pointers can be moved by clicking and dragging.';
  983.                             dp^.argtype := _none;
  984.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  985.                             settextstyle(smallfont, horizdir, 4);
  986.                             dialog_box(dialoghead, dialogbcolor, dialogcolor, True);
  987.                             dispose_dialog(dialoghead);
  988.                             New(dp);
  989.                             dp^.title :=
  990. 'Edit options remain invisible until a region is marked in the waveform box. Paste and mix';
  991.                             dp^.argtype := _none;
  992.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  993.                             New(dp);
  994.                             dp^.title :=
  995. 'must be preceded by a Cut or Copy operation and a destination region must have been';
  996.                             dp^.argtype := _none;
  997.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  998.                             New(dp);
  999.                             dp^.title :=
  1000. 'marked in the waveform box.';
  1001.                             dp^.argtype := _none;
  1002.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  1003.                             New(dp);
  1004.                             dp^.title :=
  1005. 'The Quit option is available under the File Heading.';
  1006.                             dp^.argtype := _none;
  1007.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  1008.                             dialoghead := Nil;
  1009.                             New(dp);
  1010.                             dp^.title :=
  1011. 'All configurable options are available from the settings box under the options heading.';
  1012.                             dp^.argtype := _none;
  1013.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  1014.                             New(dp);
  1015.                             dp^.title :=
  1016. 'The Zoom option under the edit heading allows fine detail to be edited after a region has';
  1017.                             dp^.argtype := _none;
  1018.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  1019.                             New(dp);
  1020.                             dp^.title :=
  1021. 'been marked. When zoom is active, the right mouse button allows direct editing of the';
  1022.                             dp^.argtype := _none;
  1023.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  1024.                             New(dp);
  1025.                             dp^.title :=
  1026. 'waveform by drawing.';
  1027.                             dp^.argtype := _none;
  1028.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  1029.                             New(dp);
  1030.                             dp^.title :=
  1031. 'When a song is in progress, the right shift key temporarily restores mouse movement to';
  1032.                             dp^.argtype := _none;
  1033.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  1034.                             New(dp);
  1035.                             dp^.title :=
  1036. 'allow alterations such as pitch and time. A song can be ended by pressing Ctrl.';
  1037.                             dp^.argtype := _none;
  1038.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  1039.                             New(dp);
  1040.                             dp^.title :=
  1041. 'Manual mouse control is available from arrow keys, and left shift allows fine control.';
  1042.                             dp^.argtype := _none;
  1043.                             add_dialogentry(dp, lastdialogentry, dialoghead);
  1044.                             settextstyle(smallfont, horizdir, 4);
  1045.                             dialog_box(dialoghead, dialogbcolor, dialogcolor, True);
  1046.                             dispose_dialog(dialoghead);
  1047.                             mousearrowoff;
  1048.                             remove_menu_column(i);
  1049.                             draw_cutbox;
  1050.                             mousearrowon;
  1051.                           End;
  1052.  
  1053.                         play_sound :
  1054.                           Begin   {play sound immediately}
  1055.                             If default_kbdmap = 'guitar' Then
  1056.                               increment := get_inc(tune, 'E')
  1057.                               {default playback pitch}
  1058.                             Else
  1059.                               increment := get_inc(tune, 'B');
  1060.                             kbdflag := 0;
  1061.                             Release := False;
  1062.                             enable_custom_kbd;
  1063.                             replay_sound(timer);
  1064.                             kbdmode := False;
  1065.                             Release := True;
  1066.                             reset_mouse; {key release might have been
  1067.                                           missed with com port disabled}
  1068.                             mousearrowoff;
  1069.                             draw_menu_box(i, j, False);
  1070.                                          {restore submenu selection}
  1071.                             mousearrowon;
  1072.                           End;
  1073.  
  1074.                         settings :
  1075.                           Begin
  1076.                             display_status;
  1077.                             mousearrowoff;
  1078.                             update_settings;
  1079.                             remove_menu_column(i);
  1080.                             draw_cutbox;
  1081.                             mousearrowon;
  1082.                           End;
  1083.  
  1084.                         {$ifdef sample}
  1085.                         _sample :
  1086.                           Begin
  1087.                             mousearrowoff;
  1088.                             k := tconstant;
  1089.                             tconstant := Round(1.19318e3/samplerate);
  1090.  
  1091. {$ifdef pwm}
  1092.                             bufstart := Ofs(bufferw^);
  1093.                             bufloop := bufstart;
  1094.                             bufend := Ofs(bufferw^[bufflength]);
  1095. {$else}
  1096.                             bufstart := Ofs(buffer^);
  1097.                             bufloop := bufstart;
  1098.                             bufend := Ofs(buffer^[bufflength]);
  1099. {$endif}
  1100.  
  1101.                             tune := incdef;
  1102.                             leftord := 0;
  1103.                             loopord := leftord;
  1104.                             rightord := bufflength;
  1105.                             j := Port[daout]; {kill value from last time}
  1106.                             If trigger > 0 Then
  1107.                               display_message('Waiting for trigger...',
  1108.                                               hotbcolor, hotcolor, storagep,
  1109.                                               True)
  1110.                             Else
  1111.                               display_message('Sampling...',
  1112.                                               hotbcolor, hotcolor, storagep,
  1113.                                               True);
  1114.                             Release := False;
  1115.                             sample;
  1116.                             Release := True;
  1117.                             If trigger > 0 Then
  1118.                               display_message('Waiting for trigger...',
  1119.                                               hotbcolor, hotcolor, storagep,
  1120.                                               False)
  1121.                             Else
  1122.                               display_message('Sampling...',
  1123.                                               hotbcolor, hotcolor, storagep,
  1124.                                               False);
  1125.                             set_bounds;
  1126.                             remove_menu_column(i);
  1127.                             draw_wave;
  1128.                             If default_kbdmap = 'guitar' Then
  1129.                               increment := get_inc(tune, 'E')
  1130.                               {default playback pitch}
  1131.                             Else
  1132.                               increment := get_inc(tune, 'B');
  1133.                             tconstant := k;
  1134.                             enable_custom_kbd;
  1135.                             Release := False;
  1136.                             replay_sound(timer);
  1137.                             Release := True;
  1138.                             kbdmode := False;
  1139.                             cutboxactive := False;
  1140.                             activate_menu_options(False);
  1141.                                                {disable cut box options}
  1142.                             mousearrowon;
  1143.                             reset_mouse;
  1144.                           End;
  1145.                         {$endif}
  1146.  
  1147.                         read_sound_file :
  1148.                           Begin
  1149.                             pickfile('SND', str1);
  1150.                             mousearrowoff;
  1151.                             If str1 <> '' Then
  1152.                             Begin
  1153.                               settextstyle(defaultfont, horizdir, 1);
  1154.                               display_message('Reading file, please wait...',
  1155.                                               dialogbcolor, dialogcolor,
  1156.                                               storagep, True);
  1157.                               mousearrowon;
  1158.                               If cutboxactive Then
  1159.                                 load_sound_file(str1, cutleft, cutright, False)
  1160.                               Else
  1161.                                 load_sound_file(str1, index(plotxoffset),
  1162.                                                 index(getmaxx-plotxoffset),
  1163.                                                 False);
  1164.                               mousearrowoff;
  1165.                               display_message('Reading file, please wait...',
  1166.                                               dialogbcolor, dialogcolor,
  1167.                                               storagep, False);
  1168.                             End;
  1169.                             update_display;
  1170.                             cutboxactive := False;
  1171.                             activate_menu_options(False);
  1172.                                               {disable cut box options}
  1173.                             mousearrowon;
  1174.                             settextstyle(smallfont, horizdir, 4);
  1175.                           End;
  1176.  
  1177.                         directory :
  1178.                           Begin
  1179.                             mousearrowoff;
  1180.                             showdirectory('*');
  1181.                             c := continue_prompt(-cornersize, -1,
  1182.                                                  dialogbcolor, dialogcolor);
  1183.                             update_display;
  1184.                             draw_cutbox;
  1185.                             mousearrowon;
  1186.                           End;
  1187.  
  1188.                         write_sound_file :
  1189.                           Begin
  1190.                             New(dp);
  1191.                             With dp^ Do
  1192.                             Begin
  1193.                               title := 'Name of output file (.snd):';
  1194.                               argtype := _string;
  1195.                               ssize := 30;
  1196.                               stringresult := '';
  1197.                               next := Nil;
  1198.                             End;
  1199.                             settextstyle(defaultfont, horizdir, 1);
  1200.                             dialog_box(dp, dialogbcolor, dialogcolor, False);
  1201.                             If (dp^.stringresult <> '') Then
  1202.                               write_data(dp^.stringresult, leftord, rightord);
  1203.                             mousearrowoff;
  1204.                             remove_menu_column(i);
  1205.                             mousearrowon;
  1206.                             Dispose(dp);
  1207.                           End;
  1208.  
  1209.                         quit_to_dos :
  1210.                           Begin
  1211.                             New(dp);
  1212.                             With dp^ Do
  1213.                             Begin
  1214.                               title := 'Are you sure you want to quit?';
  1215.                               argtype := _boolean;
  1216.                               booleanresult := True;
  1217.                               next := Nil;
  1218.                             End;
  1219.                             settextstyle(defaultfont, horizdir, 1);
  1220.                             dialog_box(dp, dialogbcolor, dialogcolor, False);
  1221.                             goodbye := dp^.booleanresult;
  1222.                             Dispose(dp);
  1223.                             mousearrowoff;
  1224.                             remove_menu_column(i);
  1225.                             mousearrowon;
  1226.                           End;
  1227.  
  1228.                       Else
  1229.                         Begin
  1230.                           closegraph;
  1231.                           WriteLn('Invalid menu option selected');
  1232.                           Halt;
  1233.                         End;
  1234.                       End;        {case}
  1235.                       While keypressed Do c := readkey;
  1236.                       enable_custom_kbd;
  1237.                       kbdflag := 0;
  1238.                       keyval := 127;
  1239.                       Repeat Until mousekeys = 0;
  1240.                                   {wait for button release if relevant}
  1241.                     End;
  1242.                   End;
  1243.                 End;
  1244.             End;
  1245.           End;
  1246.         End;
  1247.       If keypress And (scanmap[keyval] In [sprshift]) Then
  1248.         If mem[0:$417] And 1 = 0 Then {incase shift release lost while}
  1249.           kbdflag := 0;           {kbdmode was off, forget shift}
  1250.     End;
  1251.   Until goodbye;
  1252.   closegraph;
  1253.   gotoxy(1, 23);
  1254.   Assign(f, clipboardfilename);
  1255.   {$i-} Reset(f); {$i+}
  1256.   If IoResult = 0 Then
  1257.   Begin
  1258.     Close(f);
  1259.     Erase(f)                      {erase clipboard file if it exists}
  1260.   End;
  1261.   Write('Exiting...');
  1262.   showerrormessage := False;
  1263.   restore;
  1264.   mem[0:$417] := mem[0:$417] And $fc; {shift off}
  1265. End.
  1266.